#include "mongoose.h"
#include "macaddr.h"

// 服务器WebSocket地址
static const char* server_url = "wss://api.tenclass.net/xiaozhi/v1/";
// 录音程序UDP地址
static const char* recorder_url = "udp://127.0.0.1:8888";
// 播放程序UDP地址
static const char* player_url = "udp://127.0.0.1:8889";
// MCP代理程序TCP地址
static const char* mcp_url = "tcp://127.0.0.1:8080";
// WebSocket连接请求头
static const char* headers = "\
Authorization: Bearer test-token\r\n\
Protocol-Version: 1\r\n\
Device-Id: %s\r\n\
Client-Id: b20a714c-1b32-11f0-b8cd-d38cb6f1af81\r\n";
char macaddr[MACADDR_LEN];

// 小智客户端信息结构体
struct xzinfo {
    struct mg_connection * server;   // 与服务器的连接
    struct mg_connection * recorder; // 与录音程序的连接
    struct mg_connection * player;   // 与播放程序的连接
    struct mg_connection * mcp_proxy;// 与MCP代理程序的连接
    char* session_id;                // 会话ID
    int audio_up;                    // 音频上传标志，1表示可以上传音频
};

// 处理连接错误
static void handle_error(struct mg_connection *c, void *ev_data)
{
    printf("错误: %d %s\n", c->id, (char *)ev_data);
}

// 处理连接成功事件
static void handle_connect(struct mg_connection *c)
{
    struct xzinfo* xz = c->fn_data;
    if (c == xz->server && mg_url_is_ssl(server_url))
    {
        // TCP连接成功后进行TLS握手
        //printf("secure connection\n");
        struct mg_tls_opts opts = {.name = mg_url_host(server_url)};
        mg_tls_init(c, &opts);
    }
}

// 处理WebSocket连接打开事件
static void handle_ws_open(struct mg_connection *c)
{
    printf("ws handshake success\n");
    // ws握手成功后发送hello消息，初始化连接
    const char* hello_msg = "\
    {\
        \"type\": \"hello\",\
        \"version\": 1,\
        \"features\": {\
            \"mcp\": true\
        },\
        \"transport\": \"websocket\",\
        \"audio_params\": {\
            \"format\": \"opus\",\
            \"sample_rate\": 16000,\
            \"channels\": 1,\
            \"frame_duration\": 60\
        }\
    }";
    mg_ws_printf(c, WEBSOCKET_OP_TEXT, hello_msg);
}

// 处理WebSocket二进制消息（从服务器接收的音频数据）
static void handle_ws_binmsg(struct mg_connection *c, struct mg_ws_message *wm)
{
    struct xzinfo* xz = c->fn_data;
    if (xz->player) {
        // 将音频数据转发给播放程序
        mg_send(xz->player, wm->data.buf, wm->data.len);
    }
}

// 处理服务器的hello响应消息
static void handle_hello(struct mg_connection *c, struct mg_ws_message *wm)
{
    struct xzinfo* xz = c->fn_data;
    // 解析服务器返回的音频参数
    long sample_rate = mg_json_get_long(wm->data, "$.audio_params.sample_rate", 0);
    long channels = mg_json_get_long(wm->data, "$.audio_params.channels", 0);
    long duration = mg_json_get_long(wm->data, "$.audio_params.frame_duration", 0);
    printf("sample rate: %d, channels: %d, duration: %d\n", sample_rate, channels, duration);
    // 保存会话ID
    xz->session_id = mg_json_get_str(wm->data, "$.session_id");
    // 发送开始监听消息
    char* listen_msg = "{\"session_id\":\"\",\"type\":\"listen\",\"state\":\"start\",\"mode\":\"auto\"}";
    mg_ws_printf(c, WEBSOCKET_OP_TEXT, listen_msg);
    // 设置允许上传音频标志
    xz->audio_up = 1;
}

// 处理TTS（文本转语音）消息
static void handle_tts(struct mg_connection *c, struct mg_ws_message *wm)
{
    struct xzinfo* xz = c->fn_data;
    char* state = mg_json_get_str(wm->data, "$.state");
    if (state)
    {
        if (strcmp(state, "start") == 0)
        {
            // 开始播放语音，暂停上传音频
            xz->audio_up = 0;
        }

        if (strcmp(state, "stop") == 0)
        {
            sleep(1);
            // 语音播放结束，重新开始监听
            char listen_msg[100];
            mg_ws_printf(c, WEBSOCKET_OP_TEXT, 
                "{\"session_id\":\"%s\",\"type\":\"listen\",\"state\":\"start\",\"mode\":\"auto\"}", xz->session_id);
            xz->audio_up = 1;
        }

        if (strcmp(state, "sentence_start") == 0)
        {
            // 获取TTS文本内容并打印
            char* text = mg_json_get_str(wm->data, "$.text");
            if (text)
            {
                printf("%s\n", text);
                free(text);
            }
        }

        free(state);
    }
}

// 处理MCP消息
static void handle_mcp(struct mg_connection *c, struct mg_ws_message *wm)
{
    struct xzinfo* xz = c->fn_data;
    struct mg_str payload = mg_json_get_tok(wm->data, "$.payload");
    if (payload.buf)
    {
        printf("MCP Client: %.*s\n", payload.len, payload.buf);
        mg_printf(xz->mcp_proxy, "%.*s\n", payload.len, payload.buf);
    }
}

// 处理WebSocket文本消息
static void handle_ws_txtmsg(struct mg_connection *c, struct mg_ws_message *wm)
{
    printf("msg: %.*s\n", wm->data.len, wm->data.buf);
    struct xzinfo* xz = c->fn_data;
    // 根据消息类型分发处理
    char* type = mg_json_get_str(wm->data, "$.type");
    if (type)
    {
        if (strcmp(type, "hello") == 0)
        {
            handle_hello(c, wm);
        }
        
        if (strcmp(type, "tts") == 0)
        {
            handle_tts(c, wm);
        }

        if (strcmp(type, "mcp") == 0)
        {
            handle_mcp(c, wm);
        }

        free(type);
    }
}

// 处理WebSocket消息
static void handle_ws_msg(struct mg_connection *c, struct mg_ws_message *wm)
{
    if (wm->flags & WEBSOCKET_OP_BINARY)
    {
        // 处理二进制消息（音频数据）
        handle_ws_binmsg(c, wm);
    }
    
    if (wm->flags & WEBSOCKET_OP_TEXT)
    {
        // 处理文本消息（控制命令）
        handle_ws_txtmsg(c, wm);
    }
}

// 处理读取事件
static void handle_read(struct mg_connection *c)
{
    struct xzinfo* xz = c->fn_data;
    if (c == xz->recorder) {
        if (xz->server && xz->audio_up)
        {
            // 将从录音程序接收的音频数据发送给服务器
            mg_ws_send(xz->server, c->recv.buf, c->recv.len, WEBSOCKET_OP_BINARY);
        }
        c->recv.len = 0;  // 清空缓冲区
    }

    //转发MCP服务器消息
    if (c == xz->mcp_proxy) {
        printf("MCP Server: %.*s\n", c->recv.len, c->recv.buf);
        mg_ws_printf(xz->server, WEBSOCKET_OP_TEXT, "{\"type\":\"mcp\",\"payload\":%.*s,\"session_id\":\"%s\"}", c->recv.len, c->recv.buf, xz->session_id);
        c->recv.len = 0;  // 清空缓冲区
    }
}

// 处理连接关闭事件
static void handle_close(struct mg_connection *c)
{
    struct xzinfo* xz = c->fn_data;
    printf("connection %d closed\n", c->id);
    printf("reconnecting...\n");
    // 尝试重新连接服务器
    xz->server = mg_ws_connect(c->mgr, server_url, c->fn, xz, headers, macaddr);
}

// Mongoose事件处理函数
static void fn(struct mg_connection *c, int ev, void *ev_data)
{
    //if (ev != MG_EV_POLL) printf("event %x\n", ev);
    switch (ev)
    {
        case MG_EV_OPEN:
            //if (!c->is_udp) c->is_hexdumping = 1;
            break;
        case MG_EV_ERROR:
            handle_error(c, ev_data);
            break;
        case MG_EV_CONNECT:
            handle_connect(c);
            break;
        case MG_EV_WS_OPEN:
            handle_ws_open(c);
            break;
        case MG_EV_WS_MSG:
            handle_ws_msg(c, (struct mg_ws_message *) ev_data);
            break;
        case MG_EV_READ:
            handle_read(c);
            break;
        case MG_EV_CLOSE:
            handle_close(c);
            break;
    }
}

int main()
{
    struct xzinfo xz = {0};
    struct mg_mgr mgr;

    get_macaddr(macaddr);

    mg_mgr_init(&mgr);
    //mgr.dns4.url = "udp://114.114.114.114:53";
    xz.server   = mg_ws_connect(&mgr, server_url, fn, &xz, headers, macaddr);
    xz.recorder = mg_listen(&mgr, recorder_url, fn, &xz);
    xz.player   = mg_connect(&mgr, player_url, fn, &xz);
    xz.mcp_proxy = mg_connect(&mgr, mcp_url, fn, &xz);
    while (1)
        mg_mgr_poll(&mgr, 1000);
    mg_mgr_free(&mgr);
    return 0;
}
